package com.wei800.common.util;
public class SnowFlakeUtils { 				// 雪花算法工具类
    private final static long START_STAMP = 1487260800000L; // 2017-02-17 21:35:27.915
    private final static long SEQUENCE_BIT = 12; 		// 序列号占用的位数
    private final static long MACHINE_BIT = 5; 		// 机器标识占用的位数，256个机器
    private final static long DATACENTER_BIT = 5; 		// 数据中心占用位数，256个数据
    private final static long MAX_DATACENTER_NUM =
            -1L ^ (-1L << DATACENTER_BIT); 			// 数据中心最大值（31）
    private final static long MAX_MACHINE_NUM =
            -1L ^ (-1L << MACHINE_BIT); 			// 机器标识最大值（31）
    private final static long MAX_SEQUENCE =
            -1L ^ (-1L << SEQUENCE_BIT); 			// 序列号最大值（4095）
    private final static long MACHINE_LEFT = SEQUENCE_BIT; 	// 左位移
    private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT; // 左位移
    private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT; // 左位移
    private long datacenterId;  				// 数据中心
    private long machineId;     				// 机器标识
    private long sequence = 0L; 				// 序列号
    private long lastStamp = -1L; 				// 上次时间戳
    /**
     * 构建雪花算法生成器实例
     * @param datacenterId 数据中心ID
     * @param machineId    // 机器ID
     */
    public SnowFlakeUtils(long datacenterId, long machineId) {
        if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {
            throw new IllegalArgumentException("datacenterId can't be greater than " +
                    MAX_DATACENTER_NUM + " or less than 0");
        }
        if (machineId > MAX_MACHINE_NUM || machineId < 0) {
            throw new IllegalArgumentException("machineId can't be greater than " +
                    MAX_MACHINE_NUM + " or less than 0");
        }
        this.datacenterId = datacenterId; 			// 属性初始化
        this.machineId = machineId; 			// 属性初始化
    }
    public synchronized long nextId() { 			// 获取下一个ID
        long currentStamp = getCurrentStamp();		// 获取当前时间戳
        if (currentStamp < this.lastStamp) { 		// 时间戳判断
            throw new RuntimeException("Clock moved backwards.  Refusing to generate id");
        }
        if (currentStamp == lastStamp) { 			// 相同毫秒内，序列号自增
            this.sequence = (this.sequence + 1) & MAX_SEQUENCE;
            if (this.sequence == 0L) { 			// 同一毫秒的序列数已经达到最大
                for (int i = 0; i < 100; i++) { 		// 循环获取多几次，尽量避免重复
                    currentStamp = getNextMillis();		// 获取下一个时间戳
                    if (currentStamp != this.lastStamp) { 	// 结束判断
                        break; 				// 退出循环
                    }
                }
            }
        } else { 						// 不同毫秒内，序列号置为0
            this.sequence = 0L;
        }
        this.lastStamp = currentStamp; 			// 保存当前时间戳
        return (currentStamp - START_STAMP) << TIMESTMP_LEFT //时间戳部分
                | datacenterId << DATACENTER_LEFT       	//数据中心部分
                | machineId << MACHINE_LEFT             	//机器标识部分
                | sequence;                             		//序列号部分
    }
    private long getNextMillis() {
        long mills = getCurrentStamp();			// 获取当前时间戳
        while (mills <= this.lastStamp) { 			// 如果小于最后一次获取的时间戳
            mills = getCurrentStamp();			// 重新获取时间戳
        }
        return mills; 					// 返回时间戳
    }
    private long getCurrentStamp() { 			// 获取当前时间戳
        return System.currentTimeMillis();
    }
    public static long getId() { 				// 获取ID
        SnowFlakeUtils idGenerator = new SnowFlakeUtils(1, 1);
        return idGenerator.nextId();
    }
}
